/**
 * @Author: 陈瑞鹏
 * @Date:   2022-12-10 09:43:23
 * @Last Modified by:   陈瑞鹏
 * @Last Modified time: 2022-12-10 10:07:47
 */

export interface configObj {
  url: string,
  method: string,
  timetout: number,
  responseType: any,
  data: any,
  headers: any,
}

export default class HttpPromise {

  private static _ins: HttpPromise = null;

  public static get ins(): HttpPromise {
    if (this._ins == null) {
      this._ins = new HttpPromise();
    }
    return this._ins;
  }



  private BASE_URL: string = "";

  /*
    使用promise 封装XMLHttpRequest
    (resove, reject) 对应请求的(then,catch)
    config 请求参数
    data 可选
    url  必须
    method 必须
    timetout 可选默认（3000）
    responseType 可选
    使用时，then先后catch
 */
  public xhrRequest(config: configObj) {

    return new Promise((resolve, reject) => {

      if (!config.url) {

        return reject(this.createError('请求的URL不存在', config))
      }

      if (!config.method) {

        return reject(this.createError('请求的METHOD不存在', config));
      }


      let request = new XMLHttpRequest();

      let me = this;

      let URL = this.BASE_URL + config.url;

      let method = config.method.toUpperCase();

      request.open(method, URL, true);

      if (config.headers) {

        this.setHttpHeaders(request, config.headers);
      }

      let requestData = null;

      let data = config.data;

      if (config.headers && config.headers["Content-Type"] == "application/x-www-form-urlencoded") {

        requestData = '';

        for (const key in data) {

          requestData += key + "=" + data[key] + "&";
        }

      } else {

        requestData = new FormData();

        for (const key in data) {

          requestData.append(key, data[key]);
        }
      }


      request.timeout = config.timetout || 3000;

      request.onreadystatechange = () => {

        if (!request || request.readyState !== 4) {

          return;
        }

        if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file') === 0)) {

          return;
        }

        //进度
        request.upload.onprogress = function (res) {

        }

        //浏览器取消
        request.onabort = function (res) {

          if (!request) {

            return;
          }

          reject(me.createError('请求取消', config, 'ECONNABORTED', request));

          request = null;
        }

        //网络错误
        request.onerror = function (res) {

          reject(me.createError("网络错误", config, null, request));

          request = null;
        }

        //请求超时
        request.ontimeout = function (res) {

          let timeoutErrorMessage = '请求超时' + config.timetout + "ms";

          reject(me.createError(timeoutErrorMessage, config, 'ECONNABORTED', request));

          request = null;
        }
        // request.status 可能的状态码
        // 404
        // 200
        // 500
        const state = request.status;

        const stateString = {
          404: '请求的网页不存在！',
          500: '服务不可用！'
        }

        if (state == 404 || state == 500) {

          reject(me.createError("请求错误，类型" + stateString[state], config));

          request = null;

          return;
        }

        let responseHeaders = 'getAllResponseHeaders' in request ? me.parseHeaders(request.getAllResponseHeaders()) : null;

        let responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;

        let response = {
          data: JSON.parse(responseData),
          status: request.status,
          statusText: request.statusText,
          headers: responseHeaders,
          config: config,
          request: request,
        }

        me.settle(resolve, reject, response);

        request = null;
      }

      if (requestData === undefined) {
        requestData = null
      }
      // Send the request
      request.send(requestData)
    })
  }

  /**
  * 设置请求头
  * 例 setRequestHeader("Content-Type","application/x-www-form-urlencoded");
  * application/x-www-form-urlencoded
  * multipart/form-data
  * application/json
  * application/xml 和 text/xml
  * @param xhr 
  * @param headers 
  */
  private setHttpHeaders(xhr: XMLHttpRequest, headers: any) {

    for (let key in headers) {

      xhr.setRequestHeader(key, headers[key]);
    }
  }

  private settle(resolve = null, reject = null, response = null) {

    if (response.status == 200) {

      resolve(response);
    } else {

      reject(
        this.createError(
          '请求异常,状态码为:' + response.status,
          response.config,
          null,
          response.request,
          response
        )
      )
    }
  }

  private createError(message = null, config = null, code = null, request = null, response = null) {

    let error = { error: message };

    return this.enhanceError(error, config, code, request, response);
  }

  private enhanceError(error = null, config = null, code = null, request = null, response = null) {

    error.config = config;

    if (code) {

      error.code = code;
    }

    error.request = request;

    error.response = response

    error.isAxiosError = true

    error.toJSON = function () {

      return {
        message: this.message,
        name: this.name,
        description: this.description,
        number: this.number,
        fileName: this.fileName,
        lineNumber: this.lineNumber,
        columnNumber: this.coloumnNumber,
        stack: this.stack,
        config: this.config,
        code: this.code
      }
    }

    return error;
  }

  private parseHeaders(headers = null) {

    let obj = {};

    let arr = headers.split(/[(\r\n)\r\n]+/);

    arr.pop();

    arr.forEach(item => {

      let rp = item.split(':', 2);

      obj[rp[0]] = rp[1].substr(1);

    });

    return obj;
  }
}